---
title: 升级 WebSocket 🌐
description: Feat WebSocket
sidebar:
    order: 5
---

import upgrade_ws_1 from './img/upgrade_ws_1.png';
import CheckAuthorize from '../../../components/CheckAuthorize.astro'

<CheckAuthorize/>

Feat 支持通过通过 **HttpRequest.upgrade** 方法将 HTTP 请求升级为 WebSocket。

操作示例如下：
```java title=WebSocketDemo.java "upgrade"
public class WebSocketDemo {
    public static void main(String[] args) {
        Feat.httpServer().httpHandler(request -> {
            request.upgrade(new WebSocketUpgrade() {
                @Override
                public void handleTextMessage(WebSocketRequest request, WebSocketResponse response, String message) {
                    response.sendTextMessage("接受到客户端消息：" + message);
                }
            });
        }).listen();
    }
}
```

启动程序后，可访问：<a target="_blank" href="http://www.websocket-test.com/">WebSocket 在线测试</a> 验证运行效果。

<img src={upgrade_ws_1.src} alt="hello world" width="80%" className="shadow"/>

## 构造方法
WebSocketUpgrade 提供了两个构造方法，分别如下：

```java
public WebSocketUpgrade() {
    this(120000);
}

public WebSocketUpgrade(long idleTimeout) {
    this.idleTimeout = idleTimeout;
}
```
用户可在进行 WebSocket 升级时，通过构造方法传入 **idleTimeout** 参数，设置 WebSocket 连接的空闲超时时间。
其中无参构造方法默认设置空闲超时时间为 120000 毫秒，即：2 分钟。

当 WebSocket 连接空闲时间超过 **idleTimeout** 时，Feat 会主动关闭该连接。

## 消息处理
WebSocketUpgrade 提供了两个消息处理方法，分别如下：
```java
public void handle(WebSocketRequest request, WebSocketResponse response, CompletableFuture<Object> completableFuture) throws Throwable {
    try {
        handle(request, response);
    } finally {
        completableFuture.complete(null);
    }
}

public void handle(WebSocketRequest request, WebSocketResponse response) throws Throwable {
    ...
}

```
如果用户需要采用异步方式处理 WebSocket 消息，可重写带 `CompletableFuture<Object>` 入参的 **handle** 方法，并在异步处理完成后，调用 `completableFuture.complete(null)` 方法。

若需要同步处理 WebSocket 消息，可重写 `handle(WebSocketRequest request, WebSocketResponse response) ` 方法。

为便于开发人员使用，WebSocketUpgrade 已经默认实现了 `handle(WebSocketRequest request, WebSocketResponse response)` 方法，用户可按需重写相应的方法。

```java "handleTextMessage" "handleBinaryMessage" "onClose" "onError" "handlePing" "handlePong" "handleContinueMessage"
public void handle(WebSocketRequest request, WebSocketResponse response) throws Throwable {
    try {
        switch (request.getFrameOpcode()) {
            case WebSocketUtil.OPCODE_TEXT:
                handleTextMessage(request, response, new String(request.getPayload(), StandardCharsets.UTF_8));
                break;
            case WebSocketUtil.OPCODE_BINARY:
                handleBinaryMessage(request, response, request.getPayload());
                break;
            case WebSocketUtil.OPCODE_CLOSE:
                try {
                    onClose(request, response, new CloseReason(request.getPayload()));
                } finally {
                    response.close();
                }
                break;
            case WebSocketUtil.OPCODE_PING:
                handlePing(request, response);
                break;
            case WebSocketUtil.OPCODE_PONG:
                handlePong(request, response);
                break;
            case WebSocketUtil.OPCODE_CONTINUE:
                handleContinueMessage(request, response, request.getPayload());
                break;
            default:
                throw new UnsupportedOperationException();
        }
    } catch (Throwable throwable) {
        onError(request, throwable);
    }
}
```

## 请求路由
在实际场景下，用户可能需要将不同的 WebSocket 消息路由到不同的处理方法，
以及存在 Http 请求和 WebSocket 请求共存的情况。

此时可以采用 `Router` 来实现请求路由，示例如下：
```java title=WebSocketRouterDemo.java 'route("/ws1"' 'route("/ws2"' 'route("/http"'
public class WebSocketRouterDemo {
    public static void main(String[] args) {
        Router router = new Router();
        router.route("/ws1", request -> {
            request.upgrade(new WebSocketUpgrade() {
                @Override
                public void handleTextMessage(WebSocketRequest request, WebSocketResponse response, String message) {
                    response.sendTextMessage("ws1接受到客户端消息：" + message);
                }
            });
        }).route("/ws2", request -> {
            request.upgrade(new WebSocketUpgrade() {
                @Override
                public void handleTextMessage(WebSocketRequest request, WebSocketResponse response, String message) {
                    response.sendTextMessage("ws2接受到客户端消息：" + message);
                }
            });
        }).route("/http", request -> {
            request.getResponse().write("http".getBytes());
        });
        Feat.httpServer().httpHandler(router).listen();
    }
}
```